# element ui 表格动态生成多级表头,可无限嵌套

官网的写法是el-table-column下面嵌套el-table-column,如下:

<template>
  <el-table
    :data="tableData3"
    style="width: 100%">
    <el-table-column
      prop="date"
      label="日期"
      width="150">
    </el-table-column>
    <el-table-column label="配送信息">
      <el-table-column
        prop="name"
        label="姓名"
        width="120">
      </el-table-column>
      <el-table-column label="地址">
        <el-table-column
          prop="province"
          label="省份"
          width="120">
        </el-table-column>
        <el-table-column
          prop="city"
          label="市区"
          width="120">
        </el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="300">
        </el-table-column>
        <el-table-column
          prop="zip"
          label="邮编"
          width="120">
        </el-table-column>
      </el-table-column>
    </el-table-column>
  </el-table>
</template>
12345678910111213141516171819202122232425262728293031323334353637383940

可以看出代码繁琐,重复量比较大,所以改造简单封装了下 将el-table和el-table-column独立出来 el-table封装如下: MyTable.vue

<template>
  <div class="my-table">
    <el-table :data="data">
      <my-column v-for="(item,index) in col" :key="index" :col="item"></my-column>
    </el-table>
  </div>
</template>

<script>
import MyColumn from './MyColumn'
export default {
  components: {
    MyColumn
  },
  props: {
    col: {
      type: Array
    },
    data: {
      type: Array
    }
  }
}
</script>
<style scoped>
</style> 

el-table-column封装如下: MyColumn.vue

<template>

  <el-table-column :prop="col.prop"
    :label="col.label"
    align="left">

    <template v-if="col.children">
      <my-column v-for="(item, index) in col.children"
        :key="index"
        :col="item"></my-column>
    </template>

  </el-table-column>
</template>

<script>
export default {
  name: 'MyColumn',
  props: {
    col: {
      type: Object
    }
  }
}
</script>
<style scoped>
</style>
123456789101112131415161718192021222324252627

使用

<template>
  <div>
    <my-table :col="col"
      :data="data">
    </my-table>
  </div>
</template>

<script>
import MyTable from './MyTable'
export default {
  components: {
    MyTable
  },
  data() {
    return {
      col: [
        {
          prop: 'date',
          label: '日期'
        },
        {
          label: '配送信息',
          children: [
            {
              prop: 'name',
              label: '姓名'
            },
            {
              label: '地址',
              children: [
                {
                  prop: 'province',
                  label: '省份'
                },
                {
                  prop: 'city',
                  label: '市区'
                },
                {
                  prop: 'address',
                  label: '地址'
                }
              ]
            }
          ]
        }
      ],
      data: [
        {
          date: '2016-05-03',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区金沙江路 1518 弄',
          zip: 200333
        },
        {
          date: '2016-05-02',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区金沙江路 1518 弄',
          zip: 200333
        }
      ]
    }
  }
}
</script>
<style>
</style>
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172

效果图 element ui 表格动态生成多级表头,可无限嵌套 简单封装后可以动态无限级生成嵌套的表头,唯一的一个不好的地方就是自定义模版无法用这种形式自定义模版了,不过可以用render+JSX解决,问题不大

&lt;template slot-scope="scope">
&lt;/template>
12

在线预览 https://jsfiddle.net/xmwh/1spq0kcn/

文章来源:https://blog.csdn.net/liub37/article/details/82906141

实际项目中使用

&lt;template>
	&lt;div class="p-t-10">
		&lt;el-row class="m-b-20">
			&lt;el-col :span="24" class="toolbar">
				&lt;el-form :model="filters" @submit.native.prevent :inline="true" ref="filters"> 

					 &lt;el-form-item label="活动:" :label-width="toolLabelWidth" prop="pid">
						&lt;el-select size="small" v-model="filters.pid" placeholder="请选择活动" @change="handleCurrentChange(1)">
						    &lt;el-option v-for="item in actList"
						        :key="item"
						        :label="item.title"
						        :value="item.id">
						    &lt;/el-option>
						&lt;/el-select>

					 &lt;/el-form-item> 
					&lt;el-button class="m-t-5" size="small" :type="filters.tagCode == item.code?'primary':'button'" @click="select(item.code)" 
					v-for="item in honorList"
					:key="item"

					>{{item.label}}&lt;/el-button>

					&lt;!--  &lt;el-form-item>
					 &lt;el-button    @click.native.prevent="handleCurrentChange(1)" size="small" icon="el-icon-search">查询&lt;/el-button>
					 &lt;/el-form-item> 
					 &lt;el-form-item>
					 		&lt;el-button size="small" icon="el-icon-refresh" @click="$refs.filters.resetFields()">重置&lt;/el-button>
					 &lt;/el-form-item>  -->
					&lt;el-form-item class="p-l-5">
						&lt;el-button  @click.native.prevent="exportXls" size="small" icon="el-icon-download" :loading="downloading">导出&lt;/el-button>
					&lt;/el-form-item>  
				&lt;/el-form>
			&lt;/el-col>
		&lt;/el-row>

		&lt;!--列表-->
		&lt;!-- &lt;el-table :data="users" highlight-current-row v-loading="listLoading"   style="width: 100%;" >

			&lt;el-table-column type="index"  width="80" label="序号">
				&lt;template slot-scope="scope">&lt;span>{{scope.$index+(page - 1) * size + 1}} &lt;/span>&lt;/template>
			&lt;/el-table-column>

			&lt;el-table-column prop="brand" label="案例品牌">
			&lt;/el-table-column> 

			&lt;el-table-column prop="rank" label="终审排名" width="100">
			&lt;/el-table-column> 

			&lt;el-table-column label="外部评审" align="center"> 
		
					&lt;el-table-column prop="rank" label="终审排名" width="100">
					&lt;/el-table-column> 
 
						  
			&lt;/el-table-column>
			&lt;el-table-column label="内部评审" align="center">
					&lt;el-table-column label="张三" align="center">
			
					&lt;/el-table-column>
					&lt;el-table-column label="李四" align="center">
			
					&lt;/el-table-column>
			&lt;/el-table-column>


			&lt;el-table-column prop="num" label="内部评审平均分">
			&lt;/el-table-column>
			&lt;el-table-column prop="num" label="最终得分">
			&lt;/el-table-column>
			&lt;el-table-column  label="终审链接">
				&lt;template slot-scope="scope">
					&lt;a :href="scope.row.caseDataUrl" target="_blank">
			
					&lt;el-button type="text">查看&lt;/el-button>
					&lt;/a>
				&lt;/template>
			&lt;/el-table-column>
 
		&lt;/el-table>

		&lt;el-col :span="24" class="toolbar m-t-20" v-if="users.length>0">
			&lt;el-pagination background layout="total,prev, pager, next" :current-page="page" @current-change="handleCurrentChange" :page-size="size" :total="total" style="float:right;">
			&lt;/el-pagination>
		&lt;/el-col> -->

		&lt;div v-loading="listLoading">
			&lt;my-table v-if="data.length>0"
	 		:col="col"
	 		:data="data"
	 		:page="page"
	 		:size="size"
	 		>&lt;/my-table>

	 		&lt;div class="text-center empty p-t-10 p-b-10" v-if="data.length==0">暂无数据&lt;/div>
		&lt;/div>
 
 

 		&lt;el-col :span="24" class="toolbar m-t-20" v-if="data.length>0">
			&lt;el-pagination background layout="total,prev, pager, next" :current-page="page" @current-change="handleCurrentChange" :page-size="size" :total="total" style="float:right;">
			&lt;/el-pagination>
		&lt;/el-col>



	&lt;/div>
&lt;/template>
&lt;script>
	import config from '../../../common/js/config.js';
	import dic from '../../../common/js/dic.js';
	 
	import MyTable from '../../../components/review/MyTable.vue';
	import SecColumn from './SecColumn.vue'



	export default{
		components:{ 
			MyTable,
			SecColumn
		},
		props:[],
		data(){
			return {
				toolLabelWidth:config.toolbarLabelWidth,
				formLabelWidth:config.dialogLabelWidth,
				filters: { 
					pid:'',
					track:'1', 
					tagCode:''
				},
				users: [
					{
						brand:'fdsfd',
						fs:[
							{
								name:'张三',
								num:121
							}

						]
					}
				],
				total: 0,
				page: 1,
				size:10,
				listLoading: false,
				sels: [],//列表选中列 
 

				addVisible:false,
				editVisible:false,
				detailVisible:false,

	
				editForm:{
				},
				detailForm:{
				},
	
				actid:'',
				ImportReviewCaseVisible:false,
				downloading:false,

				honorList:[],

				col:[],
				colField: [
			         {
			          prop: 'xh',
			          label: '序号',
			          width:'60'
			        },
			        {
			          prop: 'brand',
			          label: '品牌',
			        }, 

			          {
			          prop: 'rank',
			          label: '终审排名',
			        },
			         {
			          label: '外部评审',
			          align: 'center',
			          children: [
			            {
			              prop: 'name',
			              label: '姓名'
			            },
			            {
			              label: '地址',
			              prop:'province'
			            }
			          ]
			        }, 
			        {
			          label: '内部评审',
			          align: 'center',

			          children: [
			            {
			              prop: 'name',
			              label: '姓名'
			            },
			            {
			              label: '地址',
			              prop:'province'
			            }
			          ]
			        },
			        {
			          prop: 'inAverage',
			          label: '内部平均分',
			        },
			        {
			          prop: 'endScore',
			          label: '最终得分',
			        },
			        // {
			        //   prop: 'rank',
			        //   label: '评语',
			        // },
			        {
			          prop: 'caseDataUrl',
			          label: '终审资料',
			          align:'center'
			        },
			      ],

			       data: [
			        // { 
			        //   date: '2016-05-03',
			        //   name: '王小虎',
			        //   province: '上海', 
			        //   brand:'品牌1',
			        //   rank:'排名',
			        //   xh:'1',
			        //   ps:[
			        //   	{
			        //   		name:'张三',
			        //   		pf:'10'
			        //   	},
			        //   	{
			        //   		name:'李四',
			        //   		pf:'10'
			        //   	}
			        //   ]
			        // },
			        // {
			        //   date: '2016-05-02',
			        //   name: '王小虎',
			        //   province: '上海', 
			        //   brand:'品牌2',
			        //   rank:'排名',
			        //   xh:'3',
			        //    ps:[
			        //   	{
			        //   		name:'张三',
			        //   		pf:'10'
			        //   	},
			        //   	{
			        //   		name:'李四',
			        //   		pf:'10'
			        //   	}
			        //   ]


			        // }
			      ],
			      actList:[]



			}
		},
		methods:{
			select:function(code){
				this.filters = {
					...this.filters,
					...{
						tagCode:code
					}
				} 

				this.handleCurrentChange(1);
			},
			exportXls:function(){
				let params = {  
					...this.filters,
				}
				this.downloading = true;
				this.$downXls('/admin/reviewData/case/exportRank',params,'评审结果导出').then(()=>{
					this.downloading = false;
				}).catch(()=>{

					this.downloading = false;
		
				})
			},
			handleCurrentChange(val) {
				this.page = val;
				this.getUsers();
			},
			getTableTitle:function(label){

				var index = -1;
				for (var i = 0; i &lt; this.colField.length; i++) {
					if(this.colField[i].label == label){
						index = i;
						break;
					}
				}

				if(index != -1){
					return index;
				}else{
					return null;
				}

			},
			createUserField:function(data,field){
				var tmp = [];
				var s = data[0][field];
				for (var i = 0; i &lt; s.length; i++) {
					tmp.push({
						label:s[i].judgesName,
						width:'80',
						prop:field=='outList'?'outList_'+i+'_num':'inList_'+i+'_num'
					})
				}


				return tmp;
			},
			createItemTitle:function(data){ 

				var tmp1 = this.getTableTitle('外部评审');
				var tmp2 = this.getTableTitle('内部评审');

 
				if(tmp1 !== null){
					this.colField[tmp1] = {
						...this.colField[tmp1],
						...{children:this.createUserField(data,'outList')}

					}
				}

				if(tmp2 !== null){
					this.colField[tmp2] = {
						...this.colField[tmp2],
						...{children:this.createUserField(data,'inList')}

					}
				}

				this.col = this.colField;

				console.log(this.colField);

			},

			createItemValue:function(data){

				for (var i = 0; i &lt; data.length; i++) {
		
					data[i].outList.forEach((item,index)=>{

						data[i]['outList_'+index+'_num'] = item.num;
			
					})

					data[i].inList.forEach((item,index)=>{
			
						data[i]['inList_'+index+'_num'] = item.num;
			
					})

				}

			},
			//获取用户列表
			getUsers() {
				this.col = [];
				this.data = [];

				this.listLoading = true;
				let params = {

						...{current:this.page,
						size:this.size},
					...this.filters, 

				} 
				this.$post('/admin/reviewData/case/caseEffect',params).then((res)=>{
						 let { msg, code, obj } = res;

						 if(code == '00'){
							this.listLoading = false;
							this.total = obj.total;
							// this.page = Math.ceil(count/this.page);
				
							obj.records.forEach((item,index)=>{
								item.xh = index+(this.page - 1) * this.size + 1

								// item.scoreList = [
								// 	{
								// 		name:'张三',
								// 		num:10
								// 	},
								// 	{
								// 		name:'李四',
								// 		num:10
								// 	}
								// ];
								// item.scoreList1 = [
								// 	{
								// 		name:'王五',
								// 		num:10
								// 	},
								// 	{
								// 		name:'李四',
								// 		num:10
								// 	}
								// ]
							})

							obj.records.length>0 &amp;&amp; 
							this.createItemValue(obj.records);


							obj.records.length>0 &amp;&amp; 
							this.createItemTitle(obj.records);



							console.log(obj.records);

							this.data = obj.records;



						 }
				
						 
			
				}).catch(()=>{
					this.listLoading = false;


				})
			}

		},
		mounted(){

			var f1 =  new Promise((resolve, reject)=>{

				this.$post('/admin/reviewData/activity/page',{page:1,size:10000}).then(({code,data})=>{
				  
				    (code == '00') &amp;&amp; (()=>{

				    	this.filters.pid = data[0].id;
				    	this.actList = data;
				    })()



					resolve();

				}).catch(()=>{
					reject()
				})
		  
		    })

		    var f2 = new Promise((resolve, reject)=>{

					// 提名奖项
					dic.ReviewTags(false,'4000010').then(res=>{
						let { msg, code, data } = res;


						this.filters.tagCode = data[0].code;
						// this.filters.tagCode = 400001003;

			
						this.honorList = data;


						resolve();
						// this.getUsers();

					}).catch(()=>{

						reject();

					})

		    })

		    Promise.all([f1,f2]).then(()=>{ 
			    console.log('callback')
				// this.getUsers();

			})
 
   

   

		},
		created(){

		},
		computed:{

		},
		watch:{
		}
	}

&lt;/script>
&lt;style scoped>
.empty{
	font-size: 14px;
	color: #909399;
	background: #fff;
}
.tip {
	font-size: 12px;
	line-height: 16px;
	color: #999;
}
.tip i {
	color: #fc9153;
}
.op{
	font-size: 12px;
	color: #409eff;
	cursor: pointer;
}

&lt;/style>

MyTable.vue

&lt;template>
	&lt;div>
		&lt;el-table :data="data" highlight-current-row  style="width: 100%;" >

			&lt;!-- 序号这一列 再加一次才可以排到第一位  
				不知道具体原因 所以得用样式再把它隐藏掉
			-->
			&lt;el-table-column width="1" label="序号" prop="xh" class-name="hide_column">
			&lt;/el-table-column>


			&lt;my-column 
			v-for="(item,index) in col" 
			:key="item"
			:index="index" 
			:col="item"
			>&lt;/my-column> 

		&lt;/el-table> 
	&lt;/div>
&lt;/template>
&lt;script>
	import MyColumn from './MyColumn.vue'
	export default{
		name: 'MyTable',
		components:{
			MyColumn
		},
		props:['data','col','page','size'],
		data(){
			return {
			}
		},
		methods:{

		},
		mounted(){


		},
		created(){
	
		},
		computed:{

		},
		watch:{
	
		}
	}

&lt;/script>
&lt;style scoped>

&lt;/style>
&lt;style>
	.hide_column{
		width: 0;
		display: none;
	}
&lt;/style>

MyColumn.vue

&lt;template>
	&lt;div>

		 
		&lt;template v-if="col.label=='终审资料'">
			&lt;el-table-column
		    :label="col.label" :key="col"
		    :align="col.align?col.align:'left'" :width="col.width?col.width:''"> 
		    	&lt;template slot-scope="scope">
		    		&lt;a :href="scope.row.caseDataUrl" target="_blank">
		    		  &lt;el-button size="mini" type="text">查看&lt;/el-button>
		    		&lt;/a>
		    	&lt;/template>
			&lt;/el-table-column>
		&lt;/template>
		&lt;template v-else>
			&lt;el-table-column :prop="col.prop"
		    :label="col.label" :key="col"
		    :align="col.align?col.align:'left'" :width="col.width?col.width:''"> 
 	
		    &lt;template v-show="col.children" >

		      &lt;my-column v-for="(item, index) in col.children"
		        :key="item"
		        :col="item">&lt;/my-column>

		    &lt;/template>

		&lt;/el-table-column>
	
		&lt;/template>
	

	&lt;/div>
&lt;/template>
&lt;script>
	export default{
		name: 'MyColumn',
		components:{},
		props:['col','index'],
		data(){
			return {

			}
		},
		methods:{
			isArr:function(prop){

				return Object.prototype.toString.call(prop)==='[object Array]';
			}
		},
		mounted(){

		},
		created(){
	
		},
		computed:{

		},
		watch:{

			'col':function(v){
				console.log(v);
			}

		}
	}

&lt;/script>
&lt;style scoped>

&lt;/style>